// GameUpdateData.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Linq;

using Supremacy.Annotations;
using Supremacy.Diplomacy;
using Supremacy.Entities;
using Supremacy.IO.Serialization;
using Supremacy.Universe;

namespace Supremacy.Game
{
    /// <summary>
    /// Contains the data sent to the clients at the beginning of each turn.
    /// </summary>
    [Serializable]
    public class GameUpdateData : IOwnedDataSerializableAndRecreatable
    {
        #region Fields
        private int _turnNumber = 1;
        private CivilizationManager _civManager;
        private UniverseObjectSet _objects;
        private SectorClaimGrid _sectorClaims;
        private CivilizationPairedMap<DiplomacyStatus> _diplomacyStatus;
        private RelationshipMap _relationships;
        private Diplomat _diplomat;
        #endregion

        /// <summary>
        /// Updates the local game context with the data contained in this <see cref="GameUpdateData"/> instance.
        /// </summary>
        public void UpdateLocalGame([NotNull] GameContext game)
        {
            if (game == null)
                throw new ArgumentNullException("game");
            GameContext.Push(game);
            try
            {
                game.TurnNumber = _turnNumber;
                game.CivilizationManagers.Clear();
                game.CivilizationManagers.Add(_civManager);
                game.Universe.Objects = _objects;
                game.SectorClaims = _sectorClaims;
                game.DiplomacyStatus = _diplomacyStatus;
                game.Relationships = _relationships;
                game.Diplomats.Clear();
                if (_diplomat != null)
                    game.Diplomats.Add(_diplomat);
                game.OnDeserialized();
            }
            finally
            {
                GameContext.Pop();
            }
        }

        /// <summary>
        /// Creates a new <see cref="GameUpdateData"/> instance for the specified player
        /// in the given game context.
        /// </summary>
        /// <param name="game">The game context.</param>
        /// <param name="player">The player.</param>
        /// <returns>The new <see cref="GameUpdateData"/> instance.</returns>
        public static GameUpdateData Create(GameContext game, Player player)
        {
            if (game == null)
                throw new ArgumentNullException("game");
            if (player == null)
                throw new ArgumentNullException("player");

            GameUpdateData data = new GameUpdateData();

            GameContext.PushThreadContext(game);
            try
            {
                data._turnNumber = game.TurnNumber;
                data._civManager = game.CivilizationManagers[player.EmpireID];
                data._objects = game.Universe.Objects;
                data._sectorClaims = game.SectorClaims;
                data._diplomacyStatus = game.DiplomacyStatus;
                data._relationships = new RelationshipMap(
                    game.Relationships.Where(
                        o => (o.OwnerCivID == player.EmpireID) || (o.OtherCivID == player.EmpireID)));
                game.Diplomats.TryGetValue(player.EmpireID, out data._diplomat);
                data._civManager.Compact();
            }
            finally
            {
                GameContext.PopThreadContext();
            }

            return data;
        }

        #region IOwnedDataSerializable Members
        public void SerializeOwnedData(SerializationWriter writer, object context)
        {
            writer.WriteOptimized(_turnNumber);
            _objects.SerializeOwnedData(writer, context);
            writer.WriteObject(_civManager);
            writer.WriteObject(_sectorClaims);
            writer.WriteObject(_diplomacyStatus);
            writer.WriteObject(_relationships);
        }

        public void DeserializeOwnedData(SerializationReader reader, object context)
        {
            _objects = new UniverseObjectSet();
            _turnNumber = reader.ReadOptimizedInt32();
            _objects.DeserializeOwnedData(reader, context);
            _civManager = reader.Read<CivilizationManager>();
            _sectorClaims = reader.Read<SectorClaimGrid>();
            _diplomacyStatus = reader.Read<CivilizationPairedMap<DiplomacyStatus>>();
            _relationships = reader.Read<RelationshipMap>();
        }
        #endregion
    }
}
